package gspring

import (
	"errors"
	"gitee.com/hongzhaomin/gspring/core"
	"gitee.com/hongzhaomin/gspring/iface"
	"reflect"
	"sync/atomic"
)

// ======================================================================
// ======================= gspring容器启动 ===============================
// ======================================================================
var defaultGspringAppCtx atomic.Pointer[iface.ApplicationContext]

func init() {
	SetDefaultCtx(core.NewDefaultApplicationContext())
}

func SetDefaultCtx(ctx iface.ApplicationContext) {
	defaultGspringAppCtx.Store(&ctx)
}

func defaultCtx() iface.ApplicationContext {
	return *defaultGspringAppCtx.Load()
}

func Refresh(beans ...any) iface.ApplicationContext {
	loadRegisterBeans()
	defaultCtx().RegisterOriginBeans(beans)
	defaultCtx().Refresh()
	return defaultCtx()
}

func loadRegisterBeans() {
	defaultCtx().RegisterOriginBeans(registeredGspringBeans)
}

// ======================================================================
// ======================= BeanFactory方法快速调用 ========================
// ======================================================================

func GetBeanByName[T any](beanName string) T {
	refType := reflect.TypeOf((*T)(nil)).Elem()
	return defaultCtx().GetBean(beanName, refType).(T)
}

func GetBeanByType[T any](beanType T) T {
	// reflect.TypeOf()源码明确表示：如果beanType是一个接口类型，会返回nil
	refType := reflect.TypeOf(beanType)
	if refType == nil {
		// 所以如果beanType是一个接口类型，我们取指针再获取反射类型
		refType = reflect.TypeOf(&beanType)
	}
	return defaultCtx().GetBeanByRt(refType).(T)
}

//func GetGspringBean[T annotation.GspringBean]() T {
//	rt := reflect.TypeOf((*T)(nil)).Elem()
//	return GetBeanByRt[T](rt)
//}
//
//func GetBeanByRt[T any](refType reflect.Type) T {
//	return gspringAppCtx.GetBeanByRt(refType).(T)
//}

func GetBean[T any]() *T {
	refType := reflect.TypeOf((*T)(nil)).Elem()
	beanPtr := defaultCtx().GetBeanByRt(refType)
	if refType.Kind() == reflect.Ptr ||
		refType.Kind() == reflect.Interface {
		t := beanPtr.(T)
		return &t
	}
	return beanPtr.(*T)
}

func GetBeanIdentity[T any]() T {
	refType := reflect.TypeOf((*T)(nil)).Elem()
	if refType.Kind() != reflect.Ptr && refType.Kind() != reflect.Interface {
		panic(errors.New("泛型必须为指针或接口类型"))
	}
	beanPtr := defaultCtx().GetBeanByRt(refType)
	return beanPtr.(T)
}

func GetBeans[T any]() []T {
	refType := reflect.TypeOf((*T)(nil)).Elem()
	if refType.Kind() != reflect.Ptr && refType.Kind() != reflect.Interface {
		panic(errors.New("泛型必须为指针或接口类型"))
	}
	beans := defaultCtx().GetBeans(refType)
	resultBeans := make([]T, 0, len(beans))
	for _, bean := range beans {
		resultBeans = append(resultBeans, bean.(T))
	}
	return resultBeans
}
